package com.ld.control.business.task.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ld.control.business.equipment.mapper.EquipmentMapper;
import com.ld.control.business.equipment.service.EquipmentService;
import com.ld.control.business.equipment.vo.resp.EquipmentRespVo;
import com.ld.control.business.process.mapper.ProcessNodeExampleMapper;
import com.ld.control.business.process.model.ProcessNodeExampleModel;
import com.ld.control.business.process.model.ProcessNodeExampleRunningModel;
import com.ld.control.business.process.service.ProcessExampleService;
import com.ld.control.business.process.service.ProcessNodeExampleService;
import com.ld.control.business.task.mapper.TaskExampleMapper;
import com.ld.control.business.task.mapper.TaskTmpMapper;
import com.ld.control.business.task.model.TaskExampleModel;
import com.ld.control.business.task.model.TaskTmpModel;
import com.ld.control.business.task.service.SubTaskExampleService;
import com.ld.control.business.task.service.TaskExampleService;
import com.ld.control.business.task.vo.req.SubTaskExampleReqVo;
import com.ld.control.business.task.vo.req.TaskExampleReqVo;
import com.ld.control.business.task.vo.req.TaskExampleSearchReqVo;
import com.ld.control.business.task.vo.resp.TaskExampleRespVo;
import com.ld.control.business.variable.service.VariableExampleService;
import com.ld.control.exception.BusinessException;
import com.ld.control.sysenum.EquipmentStatusEnum;
import com.ld.control.sysenum.SystemVariableEnum;
import com.ld.control.sysenum.TaskStatusEnum;
import com.ld.control.utils.CommonUtils;
import com.ld.control.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 任务实例表 服务实现类
 * </p>
 *
 * @author wangfeng
 * @since 2024-05-14
 */
@Slf4j
@Service
public class TaskExampleServiceImpl extends ServiceImpl<TaskExampleMapper, TaskExampleModel> implements TaskExampleService {

    @Autowired
    private JWTUtils jwtUtils;

    @Autowired
    private TaskExampleMapper taskExampleMapper;

    @Autowired
    private SubTaskExampleService subTaskExampleService;

    @Autowired
    private TaskTmpMapper taskTmpMapper;

    @Autowired
    private ProcessExampleService processExampleService;

    @Autowired
    private ProcessNodeExampleMapper processNodeExampleMapper;

    @Autowired
    private ProcessNodeExampleService processNodeExampleService;

    @Autowired
    private EquipmentMapper equipmentMapper;

    @Autowired
    private VariableExampleService variableExampleService;


    @Transactional
    @Override
    public void add(TaskExampleReqVo reqVo) {
        long startTime = System.currentTimeMillis();
        log.info("开始创建任务实例->{}", reqVo.getName());
        Long currentUserAccountId = jwtUtils.getCurrentUserAccountId();
        TaskTmpModel taskTmpModel = taskTmpMapper.selectById(reqVo.getTaskTmpId());

        // 新增任务实例
        TaskExampleModel taskExampleModel = new TaskExampleModel();
        BeanUtils.copyProperties(reqVo, taskExampleModel);
        taskExampleModel.setStatus(TaskStatusEnum.READY.getStatus());
        taskExampleModel.setCreateBy(currentUserAccountId);
        taskExampleModel.setCreateTime(new Date());
        taskExampleMapper.insert(taskExampleModel);
        String taskExampleCode = CommonUtils.getTaskExampleCode(taskExampleModel.getId());
        taskExampleModel.setCode(taskExampleCode);
        taskExampleMapper.updateById(taskExampleModel);

        // 任务样品数量绑定到系统变量
        variableExampleService.bindTaskVariable(taskExampleModel, SystemVariableEnum.taskSampleSize.getName(), String.valueOf(reqVo.getSampleAllSize()));

        // 新增任务实例和初始化结束流程关联关系
        processExampleService.addInitAndEndProcess(taskExampleModel.getId(), reqVo.getTaskTmpId());
        // 新增子任务实例
        SubTaskExampleReqVo subTaskExampleReqVo = new SubTaskExampleReqVo();
        subTaskExampleReqVo.setTaskTmpId(reqVo.getTaskTmpId());
        subTaskExampleReqVo.setTaskExampleId(taskExampleModel.getId());
        subTaskExampleReqVo.setTaskExampleName(taskExampleModel.getName());
        subTaskExampleReqVo.setSampleAllSize(reqVo.getSampleAllSize());
        subTaskExampleReqVo.setSampleSize(taskTmpModel.getSampleSize());
        subTaskExampleReqVo.setCurrentUserAccountId(currentUserAccountId);
        subTaskExampleService.add(subTaskExampleReqVo);
        long endTime = System.currentTimeMillis();
        log.info("任务实例创建成功，id->{}，耗时：{}毫秒", taskExampleModel.getId(), (endTime - startTime));
    }

    @Override
    public IPage<TaskExampleRespVo> getPageList(TaskExampleSearchReqVo reqVo) {
        IPage<TaskExampleRespVo> iPage = new Page<>(reqVo.getCurrent(), reqVo.getSize());
        return taskExampleMapper.selectPageList(iPage, reqVo);
    }

    @Override
    public IPage<TaskExampleRespVo> getPageListByStatusList(List<Integer> statusList, Integer current, Integer size) {
        IPage<TaskExampleRespVo> iPage = new Page<>(current, size);
        return taskExampleMapper.selectPageListByStatusList(iPage, statusList);
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        log.info("task status update,id={},status={}", id, status);
        TaskExampleModel taskExampleModel = new TaskExampleModel();
        taskExampleModel.setId(id);
        taskExampleModel.setStatus(status);
        taskExampleModel.setUpdateTime(new Date());
        if (status == TaskStatusEnum.RUNNING.getStatus()) {
            taskExampleModel.setStartTime(new Date());
        }
        if (status == TaskStatusEnum.SUCCESS.getStatus()) {
            taskExampleModel.setEndTime(new Date());
        }
        taskExampleMapper.updateById(taskExampleModel);
    }

    @Override
    @Transactional
    public void runTaskExample(Long id) {
        TaskExampleModel taskExampleModel = taskExampleMapper.selectById(id);
        log.info("run_task_example,id->{},name->{}", id, taskExampleModel.getName());
        // 检查任务状态
        checkRunTaskExample(taskExampleModel);
        // 任务实例状态变成运行中
        taskExampleModel.setStatus(TaskStatusEnum.RUNNING.getStatus());
        taskExampleModel.setStartTime(new Date());
        taskExampleModel.setUpdateTime(new Date());
        taskExampleMapper.updateById(taskExampleModel);

        // 运行任务初始化流程,如果返回true则代表开始流程运行成功，直接返回
        Boolean runInitProcessExampleIsOk = processExampleService.runInitProcessExample(id);
        if (runInitProcessExampleIsOk) {
            return;
        }
        // 运行第一个子任务
        Boolean runSubTaskExampleIsOk = subTaskExampleService.runSubTaskExample(id);
        if (runSubTaskExampleIsOk) {
            return;
        }
        throw new BusinessException("实验运行失败，未找到初始化流程或子任务");
    }

    @Override
    public void pause(Long id) {
        // 任务状态变成暂停中
        updateStatus(id, TaskStatusEnum.PAUSING.getStatus());
        // 后续逻辑等运行到下个节点时候在判断
    }

    @Override
    public void restore(Long id) {
        TaskExampleModel taskExampleModel = taskExampleMapper.selectById(id);
        Integer status = taskExampleModel.getStatus();
        if (status != TaskStatusEnum.PAUSED.getStatus()) {
            throw new BusinessException("只有暂停状态的任务才能唤起！");
        }
        //1.查询此任务的所有暂停状态节点
        List<ProcessNodeExampleModel> processNodeExampleModelList = processNodeExampleMapper.selectListByTaskExampleIdAndStatus(id, TaskStatusEnum.PAUSED.getStatus());
        List<ProcessNodeExampleModel> processNodeExampleModelList2 = processNodeExampleMapper.selectListByTaskExampleIdAndStatus(id, TaskStatusEnum.ERROR.getStatus());
        processNodeExampleModelList.addAll(processNodeExampleModelList2);
        for (ProcessNodeExampleModel processNodeExampleModel : processNodeExampleModelList) {
            log.info("唤起任务:TaskExampleId:{},processNodeExampleId:{}", id, processNodeExampleModel.getId());
            Long nodeExampleId = processNodeExampleModel.getId();
            Long processExampleId = processNodeExampleModel.getProcessExampleId();
            //2.任务变成运行中
            updateStatus(id, TaskStatusEnum.RUNNING.getStatus());
            //3.子任务变成运行中
            subTaskExampleService.updateStatusByNodeId(nodeExampleId, TaskStatusEnum.RUNNING.getStatus());
            //4.流程变成运行中
            processExampleService.updateStatus(processExampleId, TaskStatusEnum.RUNNING.getStatus());
            //5.调用runNode方法
            processNodeExampleService.runNode(processNodeExampleModel);
        }
    }

    @Override
    public void termination(Long id) {
        // 如果任务是终止中，暂停中，已暂停，则直接变成终止状态
        TaskExampleModel taskExampleModel = taskExampleMapper.selectById(id);
        int status = TaskStatusEnum.STOPPING.getStatus();
        if (taskExampleModel.getStatus() == TaskStatusEnum.STOPPING.getStatus()
                || taskExampleModel.getStatus() == TaskStatusEnum.PAUSED.getStatus()
                || taskExampleModel.getStatus() == TaskStatusEnum.PAUSING.getStatus()) {
            status = TaskStatusEnum.STOP.getStatus();
        }
        updateStatus(id, status);
        // 当前子任务变成终止
        // 当前的流程变成终止状态
        // 当前节点状态变成终止状态
    }

    @Override
    public void generateEstimatedTime() {
        // 查询运行中的任务
        QueryWrapper<TaskExampleModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(TaskExampleModel.STATUS, TaskStatusEnum.RUNNING.getStatus())
                .or().eq(TaskExampleModel.STATUS, TaskStatusEnum.RUNNING.getStatus());
        List<TaskExampleModel> taskExampleModelList = taskExampleMapper.selectList(queryWrapper);
        // 查询此任务预估完成时间
        for (TaskExampleModel taskExampleModel : taskExampleModelList) {
            Integer taskEstimatedTime = taskExampleMapper.selectTaskTaskEstimatedTimeById(taskExampleModel.getId());
            taskExampleModel.setEstimatedTime(taskEstimatedTime);
            taskExampleMapper.updateById(taskExampleModel);
        }
    }

    @Override
    public List<TaskExampleRespVo> getTaskDataSelectList() {
        return taskExampleMapper.selectTaskDataSelectList();
    }

    @Override
    public Long getTaskExampleCountByStatus(Integer status) {
        QueryWrapper<TaskExampleModel> queryWrapper = new QueryWrapper<>();
        if (status != null) {
            queryWrapper.eq(TaskExampleModel.STATUS, status);
        }
        return taskExampleMapper.selectCount(queryWrapper);
    }

    private void checkRunTaskExample(TaskExampleModel taskExampleModel) {
        if (ObjectUtils.isEmpty(taskExampleModel)) {
            throw new BusinessException("任务不存在！");
        }
        Integer status = taskExampleModel.getStatus();
        if (status != TaskStatusEnum.READY.getStatus()) {
            throw new BusinessException("任务状态必须是就绪状态才能启动！");
        }
        // 查询是否有运行中的任务
        QueryWrapper<TaskExampleModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(TaskExampleModel.STATUS, TaskStatusEnum.RUNNING.getStatus());
        Long count = taskExampleMapper.selectCount(queryWrapper);
        /*if (count > 0) {
            throw new BusinessException("有正在运行的任务，不能同时运行2个任务！");
        }*/
        // 检查设备是否正常
        List<EquipmentRespVo> equipmentRespVoList = equipmentMapper.selectListByTaskExampleId(taskExampleModel.getId());
        if (!CollectionUtils.isEmpty(equipmentRespVoList)) {
            // 检查所有设备是否都上线
           for (EquipmentRespVo equipmentRespVo : equipmentRespVoList) {
               Integer equipmentStatus = equipmentRespVo.getStatus();
               if (equipmentStatus != EquipmentStatusEnum.REAL_ON_LINE.getStatus()) {
                   throw new BusinessException("设备("+equipmentRespVo.getCode()+"):"+equipmentRespVo.getName() + "异常,无法运行任务！");
               }
           }
        }
    }

}
